package com.atguigu.test.factory;

import org.springframework.context.annotation.ConfigurationClassPostProcessor;

/**
 * @author zp
 * @version 1.0
 * @description: 自定义的ConfigurationClassPostProcessor类
 * 这个类是所有的后置处理器当中优先级最高的
 * 默认实现的接口(BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor 的扫描顺序也是一样的)：
 * 1、PriorityOrdered：设置执行顺序
 *      默认的增强器执行顺序是按照：
 *      PriorityOrdered 第一次排序 优先级最高
 *      Ordered 第二次排序 优先级次之
 *      未设置任何排序接口 未做任何排序 默认顺序执行
 *
 * 2、ResourceLoaderAware： 注入资源加载器
 * 3、ApplicationStartupAware：注入容器启动器
 * 4、BeanClassLoaderAware： 注入bean的类加载器
 * 5、EnvironmentAware：注入环境变量类
 *
 * 这个类的作用：
 * 1、ConfigurationClassPostProcessor这个processor是优先级最高的被执行的processor(实现了PriorityOrdered接口)
 * 2、ConfigurationClassPostProcessor会去BeanFactory中找出所有有@Configuration注解的bean，然后使用ConfigurationClassParser去解析这个类。
 * 3、ConfigurationClassParser内部有个Map<ConfigurationClass, ConfigurationClass>类型的configurationClasses属性用于保存解析的类，
 * ConfigurationClass是一个对要解析的配置类的封装，内部存储了配置类的注解信息、被@Bean注解修饰的方法、@ImportResource注解修饰的信息、
 * ImportBeanDefinitionRegistrar等都存储在这个封装类中。
 * 4、总结下来的话 就是最优先加载配置类的配置信息 让后续类的初始化和实例化有完成的配置信息 完成后续的工作
 *
 * springboot 解析配置类的一些过程：
 * 1、处理@PropertySources注解：进行一些配置信息的解析
 * 2、处理@ComponentScan注解：使用ComponentScanAnnotationParser扫描basePackage下的需要解析的类(@SpringBootApplication注解也包括了@ComponentScan注解，
 * 只不过basePackages是空的，空的话会去获取当前@Configuration修饰的类所在的包)，并注册到BeanFactory中(这个时候bean并没有进行实例化，而是进行了注册。
 * 具体的实例化在finishBeanFactoryInitialization方法中执行)。对于扫描出来的类，递归解析
 * 3、处理@Import注解：先递归找出所有的注解，然后再过滤出只有@Import注解的类，得到@Import注解的值。比如查找@SpringBootApplication注解的@Import注解数据的话，
 * 首先发现@SpringBootApplication不是一个@Import注解，然后递归调用修饰了@SpringBootApplication的注解，发现有个@EnableAutoConfiguration注解，
 * 再次递归发现被@Import(EnableAutoConfigurationImportSelector.class)修饰，还有@AutoConfigurationPackage注解修饰，再次递归@AutoConfigurationPackage注解，
 * 发现被@Import(AutoConfigurationPackages.Registrar.class)注解修饰，所以@SpringBootApplication注解对应的@Import注解有2个，分别是@Import(AutoConfigurationPackages.Registrar.class)
 * 和@Import(EnableAutoConfigurationImportSelector.class)。找出所有的@Import注解之后，开始处理逻辑：
 * 4、遍历这些@Import注解内部的属性类集合
 * 5、如果这个类是个ImportSelector接口的实现类，实例化这个ImportSelector，如果这个类也是DeferredImportSelector接口的实现类，那么加入ConfigurationClassParser的deferredImportSelectors属性中让第6步处理。
 * 否则调用ImportSelector的selectImports方法得到需要Import的类，然后对这些类递归做@Import注解的处理
 * 6、如果这个类是ImportBeanDefinitionRegistrar接口的实现类，设置到配置类的importBeanDefinitionRegistrars属性中
 * 其它情况下把这个类入队到ConfigurationClassParser的importStack(队列)属性中，然后把这个类当成是@Configuration注解修饰的类递归重头开始解析这个类
 * 7、处理@ImportResource注解：获取@ImportResource注解的locations属性，得到资源文件的地址信息。然后遍历这些资源文件并把它们添加到配置类的importedResources属性中
 * 8、处理@Bean注解：获取被@Bean注解修饰的方法，然后添加到配置类的beanMethods属性中
 * 9、处理DeferredImportSelector：处理第3步@Import注解产生的DeferredImportSelector，进行selectImports方法的调用找出需要import的类，然后再调用第3步相同的处理逻辑处理
 *   9.1、这里@SpringBootApplication注解被@EnableAutoConfiguration修饰，@EnableAutoConfiguration注解被@Import(EnableAutoConfigurationImportSelector.class)修饰，
 *   所以在第3步会找出这个@Import修饰的类EnableAutoConfigurationImportSelector，这个类刚好实现了DeferredImportSelector接口，接着就会在第6步被执行。第6步selectImport得到的类就是自动化配置类。
 *   9.2、EnableAutoConfigurationImportSelector的selectImport方法会在spring-boot-autoconfigure包的META-INF里面的spring.factories文件中找出key为org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的值，
 *   有109个，这109个就是所谓的自动化配置类(XXXAutoConfiguration)。（如果引入了mybatis和pagehelper，也会在对应的XXXautoconfigure包的META-INF里面的spring.factories找到EnableAutoConfiguration，
 *   这样可能最后得到的自动配置类会大于109个。）然后在过滤排除一下不需要的配置，最后返回实际用到的。
 *   9.3、ConfigurationClassParser解析完成之后，被解析出来的类会放到configurationClasses属性中。然后使用ConfigurationClassBeanDefinitionReader去解析这些类。
 *
 * @date 2022/12/10 15:52
 */
public class MyConfigurationClassPostProcessor extends ConfigurationClassPostProcessor {
}
